#ifndef BIT_WIN_ROW_TEXT_TEMPLATES_H
#define BIT_WIN_ROW_TEXT_TEMPLATES_H


#include <climits>
#include <bitset>
#include <string>

#include <QString>
#include <QBitArray>

#include "row_text.h"


namespace BitWin
{


// Means to convert different data types (integral, string, bitset)
// to PRowText.
class PRowTextMaker
{

    // "0" and "1" bit literal representation
    static const QString ZERO;
    static const QString ONE;


public:

    //---- Data item wrappers base class template
    template <typename T>
    class GenericData
    {
        T _value;
    
        // Declared, but not implemented
        T& operator=(const GenericData<T>&);
        GenericData(const GenericData<T>&);
    
    protected:
    
        inline T value() const
        {
            return _value;
        }
    
        explicit GenericData(const T& value_):
            _value(value_)
        {}
    
        ~GenericData() {}
    };


    //---- Data item wrappers concreete classes templates

    template <typename T>
    class IntegralData: public GenericData<T>
    {
    public:
    
        explicit IntegralData(const T value_):
            GenericData<T>(value_)
        {}
    
        QString at(int index) const
        {
            if ((GenericData<T>::value() >> index) & 1)
                return PRowTextMaker::ONE;
            else
                return PRowTextMaker::ZERO;
        }
    
        size_t size() const
        {
            return CHAR_BIT * sizeof(T);
        }
    };


    template <typename T>
    class LiteralData: public GenericData<T>
    {
    public:
    
        explicit LiteralData(const T& value_):
            GenericData<T>(value_)
        {}
    
        QString at(int index) const
        {
            return QString(GenericData<T>::value()[index]);
        }
    
        size_t size() const
        {
            return GenericData<T>::value().size();
        }
    };


    template <typename T>
    class BitsetData: public GenericData<T>
    {
    public:
    
        explicit BitsetData(const T& value_):
            GenericData<T>(value_)
        {}
    
        QString at(int index) const
        {
            if (GenericData<T>::value()[index])
                return PRowTextMaker::ONE;
            else
                return PRowTextMaker::ZERO;
        }
    
        size_t size() const
        {
            return GenericData<T>::value().size();
        }
    };


    // RowText generic template: accept data item wrapper
    // concreete class template (see upper) and wrapped data type
    // as template arguments.
    template <template <typename> class DataClass, typename T>
    class TemplateRowText: public RowText, private DataClass<T>
    {
    public:
    
        explicit TemplateRowText(const T& data):
            DataClass<T>(data)
        {}
    
        virtual QString at(int index) const
        {
            if (
                (index >= 0) &&
                (static_cast<size_t>(index) < DataClass<T>::size())
            )
                return DataClass<T>::at(index);
            else
                return QString();
        }
    
        virtual int size() const
        {
            return DataClass<T>::size();
        }
    };


    //---- Maker unary functors - just instanciate appropriate
    // RowText child classes wrapped into PRowText smart pointers.

    // Functor generic template.
    // Partial specialized functors are childs of this class.
    template <template <typename> class DataClass, typename T>
    class TemplateRowTextMaker
    {
    protected:
    
        ~TemplateRowTextMaker() {}
    
    public:
        PRowText operator()(const T& value) const
        {
            return PRowText(
                new TemplateRowText<DataClass, T>(value)
            );
        }
    };


    // Specialized functor templates

    template <typename T>
    class FromIntegral: public TemplateRowTextMaker<IntegralData, T>
    {};


    template <typename T>
    class FromLiteral: public TemplateRowTextMaker<LiteralData, T>
    {};


    template <typename T>
    class FromBitset: public TemplateRowTextMaker<BitsetData, T>
    {};

};


const QString PRowTextMaker::ZERO("0");
const QString PRowTextMaker::ONE("1");


} // BitWin namespace end


#endif
